package panda.client.ui.widgets;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import panda.client.JSNI;
import panda.client.engine.MagicCard;
import panda.client.engine.Observable;
import panda.client.engine.PandaCollections;
import panda.client.enumerations.ZIndexLevel;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Label;

/**
 * A bin holds cards. Drag a card to a bin to put it in. Click on a bin via BinMouseListenerForBins to get it placed
 * back on PandaApp.canvas. The bottommost card is index 0, and the topmost card is index n-1. Automatically sets its
 * title to indicate size.
 * 
 * @author zane.tian@gmail.com
 */
public class Bin extends Observable {
	public static final int height = 30;
	public static final int width = 120;
	public static final int canvasPadding = 5;

	private Label binLabel;
	private String name;
	private String owner; /* clientID.getname */
	private List<DraggableCard> cards = new ArrayList<DraggableCard>();

	public Bin(String name, String owner) {
		binLabel = new Label(name);
		this.name = name;
		this.owner = owner;

		DOM.setStyleAttribute(binLabel.getElement(), "height", height + "px");
		DOM.setStyleAttribute(binLabel.getElement(), "width", width + "px");
		DOM.setStyleAttribute(binLabel.getElement(), "textAlign", "center");
		DOM.setStyleAttribute(binLabel.getElement(), "verticalAlign", "middle");
		DOM.setStyleAttribute(binLabel.getElement(), "zIndex", String.valueOf(ZIndexLevel.BIN.getZIndex()));
		// binLabel.addStyleName("bin-RoundedBorder");
		removeHover();
		JSNI.disableSelection(binLabel.getElement());

		if(this.name.equals("Graveyard")) {
			// DOM.setStyleAttribute(binLabel.getElement(), "backgroundColor", "rgb(160, 160, 180)");
		}

		if(this.name.equals("Library")) {
			// DOM.setStyleAttribute(binLabel.getElement(), "backgroundColor", "rgb(200, 200, 200)");
		}

		if(this.name.equals("Hand")) {
			// DOM.setStyleAttribute(binLabel.getElement(), "backgroundColor", "rgb(120, 150, 200)");
			// DOM.setStyleAttribute(binLabel.getElement(), "backgroundPosition", "70% 70%");
		}

		// getLabel().addMouseListener(new BinMouseListenerForBins(this));
		updateLabel();
	}
	
	public List<DraggableCard> getCards() {
		return cards;
	}

	public String getOwnerName() {
		return owner;
	}
	
	/* returns something like "Kyruru's Graveyard" or something :) */
	public String getOwnerAndType() {
		return owner + "'s " + getName();
	}

	/* set the "a card is being dragged over me" style */
	public void setHover() {
		DOM.setStyleAttribute(binLabel.getElement(), "border", "1px solid black");
		DOM.setStyleAttribute(binLabel.getElement(), "backgroundColor", "rgb(230, 230, 230)");
	}

	/* remove the "a card is being dragged over me" style */
	public void removeHover() {
		DOM.setStyleAttribute(binLabel.getElement(), "border", "1px solid rgb(180, 180, 180)");
		DOM.setStyleAttribute(binLabel.getElement(), "backgroundColor", "white");
	}

	public DraggableCard removeCardAtIndex(int index) {
		DraggableCard removed = cards.remove(index);
		setChanged();
		notifyObservers();
		updateLabel();
		return removed;
	}
	
	public DraggableCard removeCard(DraggableCard card) {
		/* should be sound, because Bin contains only unique cards (unique on serverID) */
		/* TODO you know, ideally we should have robust .equals methods for MagicCards and DraggableCards =P */
		int index = cards.indexOf(card); 
		return removeCardAtIndex(index);
	}

	public void setBinContents(List<DraggableCard> cards) {
		this.cards = cards;
		setChanged();
		notifyObservers();
		updateLabel();
	}

	public List<DraggableCard> getDraggableCardsSnapshot() {
		return Collections.unmodifiableList(cards);
	}

	public List<MagicCard> getMagicCardsSnapshot() {
		List<MagicCard> magicCards = new ArrayList<MagicCard>();
		for(DraggableCard draggableCard : cards) {
			magicCards.add(draggableCard.getMagicCard());
		}

		return magicCards;
	}

	public void addCardToTop(DraggableCard card) {
		insertCard(card, 0);
	}

	/* Note: inserts a card at index, but also flips it up if it was face down and uptaps it if tapped */
	public void insertCard(DraggableCard card, int index) {
		card.flipUp();
		card.untap();
		
		cards.add(index, card);
		setChanged();
		notifyObservers();
		updateLabel();
	}

	public DraggableCard removeTopCard() {
		if(isEmpty()) {
			throw new IllegalStateException("Cannot take a card from an empty bin: " + name);
		}

		DraggableCard card = cards.get(0);

		cards.remove(card);
		setChanged();
		notifyObservers();
		updateLabel();

		return card;
	}

	public void shuffle() {
		PandaCollections.shuffle(cards);
		setChanged();
		notifyObservers();
	}

	public Label getLabel() {
		return binLabel;
	}

	private void updateLabel() {
		binLabel.setText(name + ":" + size()/* + " " + owner*/);
	}

	public int size() {
		return cards.size();
	}

	public boolean isEmpty() {
		return cards.isEmpty();
	}

	public int getHeight() {
		return height;
	}

	public int getWidth() {
		return width;
	}

	public int getCanvasPadding() {
		return canvasPadding;
	}

	public String getName() {
		return name.toLowerCase();
	}
}